#include "app_device.h"

static device_t *s_dev = NULL;

/**
 * @brief 设备初始化
 * @param 设备的文件地址
 * @return 设备结构体
 */
device_t *app_device_init(char *dev_file_name)
{
    log_info("device init");
    device_t *dev = (device_t *)malloc(sizeof(device_t));
    if (dev == NULL)
    {
        log_error("device init error");
        return NULL;
    }
    dev->dev_file_name = dev_file_name;
    dev->dev_fd = open(dev_file_name, O_RDWR);
    if (dev->dev_fd < 0)
    {
        perror("open device error");
        return NULL;
    }
    // 缓冲区
    dev->up_buffer = app_buffer_init(1024);
    dev->down_buffer = app_buffer_init(1024);

    // 运行情况
    dev->is_running = 0;
    // 上次写入时间
    dev->last_write_ts_ms = 0;
    // 写入间隔
    dev->write_interval_ms = 200;
    dev->per_write = NULL;
    dev->post_read = NULL;
    s_dev = dev;
    log_info("device init success");
    return s_dev;
}

/**
 * @brief 启动设备读取操作
 * 1 启动从蓝牙串口中读取数据的线程 （上行线路）
 * 2 向消息队列模块中注册接收数据后的处理数据函数 （下行线路开始）
 */
int app_device_start()
{
    log_info("device start");
    if (s_dev->is_running)
    {
        log_info("device is running");
        return 0;
    }
    s_dev->is_running = 1;
    // 1 启动从蓝牙串口中读取数据的线程 （上行线路）
    if ((pthread_create(&s_dev->dev_read_thread, NULL, app_device_read, NULL)) < 0)
    {
        perror("pthread_create error");
        return -1;
    }

    // 2 向消息队列模块中注册接收数据后的处理数据函数 （下行线路开始）
    app_mqtt_register_callback(app_device_recv_from_mqtt);
    log_info("device start success");
    return 0;
}

/**
 * @brief 从蓝牙芯片中读取数据 （异步方法）1号
 * 1 从蓝牙芯片中读取数据
 * 2 要做到预处理 转换格式
 * 3 写入到上行缓冲区中
 * 4 安排线程池执行 后续工作（发送mqtt）
 */
void *app_device_read(void *arg)
{
    while (s_dev->is_running)
    {
        char read_buff[128] = {0};
        //  1 从蓝牙芯片中读取数据
        int read_size = read(s_dev->dev_fd, read_buff, 128);
        // log_info("read size:%d,s_dev->dev_fd:%d", read_size,s_dev->dev_fd);
        if (read_size <= 0)
        {
            continue;
        }
        // 接收到数据
        log_info("read data: %.*s", read_size, read_buff);
        app_common_print_hex(read_buff, read_size);
        // 2 要做到预处理 转换格式
        if (s_dev->post_read)
        {
            read_size = s_dev->post_read(read_buff, read_size);
        }

        if (read_size <= 0)
        {
            continue;
        }
        // 3 写入到上行缓冲区中
        if ((app_buffer_write(s_dev->up_buffer, read_buff, read_size)) < 0)
        {
            perror("app_buffer_write error(up)");
            continue;
        }
        // 4 安排线程池执行 后续工作（发送mqtt）
        app_pool_register_task(app_device_send2mqtt, NULL);
    }
    return NULL;
}

/**
 * @brief 从缓冲区读取到数据写入到mqtt中 （异步方法，线程池执行）2号
 * 1 从上行缓冲区中读取数据
 * 2 转换数据格式
 * 3 发送到mqtt
 */
void *app_device_send2mqtt(void *arg)
{
    // 1 从上行缓冲区中读取数据
    char read_buff[128] = {0};
    int read_size = app_buffer_read(s_dev->up_buffer, read_buff, sizeof(read_buff));

    // 2 转换数据格式
    char *json = app_message_bytes2json(read_buff, read_size);
    if (json == NULL)
    {
        return NULL;
    }

    // 3 发送到mqtt
    if ((app_mqtt_send(json, strlen(json) + 1)) < 0)
    {
        perror("app_mqtt_send error");
        return NULL;
    }

    return NULL;
}

/**
 * @brief 从mqtt中接收数据到缓冲区总 （注册给消息队列模块）3号
 * 1 把从mqtt中接收的json进行转换字节数组
 * 2 写入到下行n缓冲区
 * 3 安排线程池执行 后续工作（写入蓝牙芯片）
 */
int app_device_recv_from_mqtt(char *data, int len)
{
    // 1 把从mqtt中接收的json进行转换字节数组
    char data_buff[128] = {0};
    int data_len = app_message_json2bytes(data, data_buff, 128);

    // 写入到下行缓冲区中
    if (app_buffer_write(s_dev->down_buffer, data_buff, data_len) < 0)
    {
        perror("app_buffer_write error(down)");
        return -1;
    }

    // 安排线程池执行 后续工作（写入蓝牙芯片）
    app_pool_register_task(app_device_write, NULL);

    return 0;
}

/**
 * @brief 向蓝牙芯片中写入数据 （异步方法 线程池执行）4号
 * 1 从下行缓冲区中读取数据
 * 2 如果有数据，则进行些钱预处理
 * 3 写入到蓝牙芯片中
 */
void *app_device_write(void *arg)
{
    // 1 从下行缓冲区中读取数据
    char data_buff[128] = {0};
    int data_size = app_buffer_read(s_dev->down_buffer, data_buff, sizeof(data_buff));

    // 2 如果有数据，则进行写前预处理
    if (data_size == 0)
    {
        return NULL;
    }
    if (s_dev->per_write)
    {
        data_size = s_dev->per_write(data_buff, data_size);
    }

    // 3 写入到蓝牙芯片中
    // 写入数据之前要控制频率 必须达到间隔才能写入
    long now_ts_ms = app_common_getcurtime_ms();
    if (s_dev->last_write_ts_ms > 0)
    {
        int cur_interval_ms = now_ts_ms - s_dev->last_write_ts_ms;
        if (cur_interval_ms < s_dev->write_interval_ms)
        {
            usleep((s_dev->write_interval_ms - cur_interval_ms) * 1000); // 要求间隔-当前间隔 = 需要等待的时间
        }
    }

    if (write(s_dev->dev_fd, data_buff, data_size) < 0)
    {
        log_error("write error");
        return NULL;
    }

    return NULL;
}

/**
 * @brief 停止设备读取操作
 */
void app_device_destroy()
{
    s_dev->is_running = 0;
    pthread_cancel(s_dev->dev_read_thread);
    app_buffer_destroy(s_dev->up_buffer);
    app_buffer_destroy(s_dev->down_buffer);
    close(s_dev->dev_fd);
    free(s_dev);
}